package o2o.service.company.postman;

import com.alibaba.fastjson.JSONArray;
import com.jinyou.utils.common.DateUtils;
import com.jinyou.utils.common.JYMathDoubleUtils;
import com.jinyou.utils.common.ValidateUtil;
import com.jinyouapp.common.tools.jms.model.JMSNotify;
import o2o.cache.company.postman.PostCompanyMemory;
import o2o.cache.postman.CityPostmanMemory;
import o2o.config.dao.UserDaoSql;
import o2o.config.jms.config.JMSTypeContent;
import o2o.config.jms.sender.JmsSender;
import o2o.dao.PO.PojoTables;
import o2o.dao.PO.company.postman.PostCompanyInfo;
import o2o.dao.PO.company.postman.PostCompanySalaryCalcInfo;
import o2o.dao.PO.company.postman.PostCompanySalaryCountRuleInfo;
import o2o.postman.model.CityPostman;
import org.apache.commons.lang.StringUtils;

import java.sql.Connection;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author Jahnke【1029777564@qq.com】
 * @ClassName DeliverCompanySalarySerivce
 * @Description: 配送公司-配送费用设置管理
 * @date 2019/8/19 9:59
 * @Version 1.0
 */
public class DeliverCompanySalarySerivce {

    private DeliverCompanySalarySerivce() {
    }

    enum Singleton {
        INSTANCE;
        private DeliverCompanySalarySerivce single;

        private Singleton() {
            single = new DeliverCompanySalarySerivce();
        }

        private DeliverCompanySalarySerivce getInstance() {
            return single;
        }
    }

    public static DeliverCompanySalarySerivce getInstance() {
        return Singleton.INSTANCE.single;
    }

    private static Map<Long, List<PostCompanySalaryCountRuleInfo>> countRuleMap = new ConcurrentHashMap<>();            // 配送公司的设置

    // 获取配送公司的配送费规则
    public Map<String, Object> getDeliverySalarySetting(String sysCustomer, Long companyId) throws Exception {
        PostCompanyInfo postCompanyInfo = PostCompanyMemory.getInstance().getById(companyId);
        if (postCompanyInfo == null) {
            throw new Exception("获取配送公司信息错误");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("deliverSalarySetting", postCompanyInfo.getDeliverSalarySetting());
        map.put("deliverySalaryproportion", postCompanyInfo.getDeliverySalaryproportion());
        map.put("deliverySalaryData", postCompanyInfo.getDeliverySalaryData());
        if (StringUtils.isNotEmpty(postCompanyInfo.getDeliverSalarySetting())) {
            List<PostCompanySalaryCountRuleInfo> orderCountRuleList = this.listOfCountRule(companyId, postCompanyInfo.getDeliverSalarySetting());
            map.put("rule", JSONArray.toJSON(orderCountRuleList == null ? Collections.emptyList() : orderCountRuleList));
        }

        return map;
    }

    // 更改配送公司的配送规则(包括抽成高比例或者累计订单的结算时间，几号)
    public void updateDeliverySalarySetting(String sysCustomer, Long companyId, String deliverSalarySetting,
                                            Double deliverySalaryproportion, Integer deliverySalaryData) throws Exception {
        PostCompanyInfo postCompanyInfo = PostCompanyMemory.getInstance().getById(companyId);
        if (postCompanyInfo == null) {
            throw new Exception("获取配送公司信息错误!");
        }
        if (!deliverSalarySetting.equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_COUNT) && !deliverSalarySetting.equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_DRAW)) {
            throw new Exception("配送费类型设置错误！");
        }
        postCompanyInfo.setDeliverSalarySetting(deliverSalarySetting);
        if (deliverSalarySetting.equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_COUNT)) {
            deliverySalaryData = deliverySalaryData == null ? 1 : deliverySalaryData;
            if (deliverySalaryData <= 0 || deliverySalaryData > 28) {
                throw new Exception("每月结算日期只能是1-28号之间！");
            }
            postCompanyInfo.setDeliverySalaryData(deliverySalaryData);
        }
        if (deliverSalarySetting.equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_DRAW)) {
            // if (deliverySalaryproportion == null || deliverySalaryproportion > 1 || deliverySalaryproportion < 0) {
            //     throw new Exception("请输入正确的抽成比例信息");
            // }
            deliverySalaryData = deliverySalaryData == null ? 1 : deliverySalaryData;
            if (deliverySalaryData <= 0 || deliverySalaryData > 28) {
                throw new Exception("每月结算日期只能是1-28号之间！");
            }
        }

        // 修改
        Connection conn = UserDaoSql.getInstance().getConnection();
        conn.setAutoCommit(false);
        try {
            UserDaoSql.getInstance().updateObj(PojoTables.POST_COMPANY, postCompanyInfo, "id", companyId);
            if (deliverSalarySetting.equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_COUNT) || deliverSalarySetting.equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_DRAW)) {
                List<PostCompanySalaryCountRuleInfo> orderCountRuleList = this.listOfCountRule(companyId, deliverSalarySetting);
                if (orderCountRuleList == null || orderCountRuleList.isEmpty()) {
                    // 自动添加一条配送数量的计算规则
                    PostCompanySalaryCountRuleInfo ruleInfo = new PostCompanySalaryCountRuleInfo();
                    ruleInfo.setRuleType(deliverSalarySetting);
                    if (deliverSalarySetting.equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_COUNT)) {
                        ruleInfo.setOrderDeliveryPrice(1D);
                    } else if (deliverSalarySetting.equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_DRAW)) {
                        ruleInfo.setOrderDeliveryPrice(0D);     // 不参与抽成
                    }
                    ruleInfo.setCompanyId(companyId).setStartOrderCount(1).setEndOrderCount(1000).setDelFlag(0).setCreateTime(System.currentTimeMillis());
                    UserDaoSql.getInstance().saveObj(PojoTables.POST_COMPANY_RULE_SALARY, ruleInfo, conn);
                }
            }
            conn.commit();

            PostCompanyMemory.getInstance().modify(postCompanyInfo.getId());
            // 数据同步
            JMSNotify notify = JMSNotify.getInstance().setType(JMSTypeContent.COMPANY_POST_INFO_UPDATE).setLong01(postCompanyInfo.getId());
            JmsSender.setTopicSender(notify);

        } catch (Exception e) {
            e.printStackTrace();
            UserDaoSql.getInstance().rollback(conn);
        } finally {
            UserDaoSql.getInstance().close(conn);
        }
    }

    // 获取配送公司的订单量配送规则
    public List<PostCompanySalaryCountRuleInfo> listOfCountRule(Long companyId, String type) {
        if (StringUtils.isEmpty(type)) {
            type = PostCompanySalaryCountRuleInfo.SALARY_RULE_TYPE_ORDERCOUNT;
        }
        List<PostCompanySalaryCountRuleInfo> list = countRuleMap.containsKey(companyId) ? countRuleMap.get(companyId) : null;
        if (list == null || list.isEmpty()) {
            // 查询数据库
            String sql = "select * from " + PojoTables.POST_COMPANY_RULE_SALARY + " where companyId=" + companyId;
            try {
                list = (List<PostCompanySalaryCountRuleInfo>) UserDaoSql.getInstance().list(PostCompanySalaryCountRuleInfo.class, sql);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            if (list != null && !list.isEmpty()) {
                countRuleMap.put(companyId, list);
            }
        }
        if (list != null) {
            String finalType = type;
            list = list.stream().filter(a -> StringUtils.isNotEmpty(a.getRuleType()) && a.getRuleType().equals(finalType)).collect(Collectors.toList());
        }
        return list;
    }

    // 添加配送公司订单量配送
    public void addRule(PostCompanySalaryCountRuleInfo info) throws Exception {
        this.validateRuleInfo(info);

        info.setCreateTime(System.currentTimeMillis());
        UserDaoSql.getInstance().saveObj(PojoTables.POST_COMPANY_RULE_SALARY, info);
        countRuleMap.remove(info.getCompanyId());
    }

    // 修改-订单量配送规则
    public void updateRule(PostCompanySalaryCountRuleInfo info) throws Exception {
        this.validateRuleInfo(info);

        UserDaoSql.getInstance().updateObj(PojoTables.POST_COMPANY_RULE_SALARY, info, "id", info.getId());
        countRuleMap.remove(info.getCompanyId());
    }

    // 删除配送公司的配送费规则设置
    public void deleteRule(Long companyId, Long id) throws Exception {
        PostCompanyInfo postCompanyInfo = PostCompanyMemory.getInstance().getById(companyId);
        if (postCompanyInfo == null) {
            throw new Exception("获取配送公司信息错误");
        }
        try {
            UserDaoSql.getInstance().delete(PojoTables.POST_COMPANY_RULE_SALARY, id);
            countRuleMap.remove(companyId);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 检测规则参数设置是否正确
    private void validateRuleInfo(PostCompanySalaryCountRuleInfo info) throws Exception {
        if (info.getRuleType().equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_COUNT)) {
            if (info.getOrderDeliveryPrice() == null || info.getOrderDeliveryPrice() <= 0) {
                throw new Exception("配送费金额错误");
            }
        }
        if (info.getRuleType().equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_DRAW)) {
            if (info.getOrderDeliveryPrice() == null || info.getOrderDeliveryPrice() <= 0 || info.getOrderDeliveryPrice() > 1) {
                throw new Exception("抽成比例错误");
            }
        }
        if (info.getRuleType().equals(PostCompanySalaryCountRuleInfo.SALARY_RULE_TYPE_BOUNS)) {
            // 判断是否存在起止时间和奖励金
            if (info.getRuleStartTime() == null || info.getRuleEndTime() == null || info.getRuleEndTime().getTime() <= info.getRuleStartTime().getTime()) {
                throw new Exception("奖励金起止时间设置错误");
            }
            if (info.getOrderDeliveryPrice() == null || info.getOrderDeliveryPrice() <= 0) {
                throw new Exception("奖励金金额错误");
            }
        }

        // 订单量和抽成需要设置订单区间  奖励金规则，不需要
        if (info.getRuleType().equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_COUNT) || info.getRuleType().equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_DRAW)) {
            if (info.getStartOrderCount() <= 0 || info.getEndOrderCount() < info.getStartOrderCount()) {
                throw new Exception("订单量起止设置错误！");
            }
        }
    }

    // 获取骑士当前订单可获取的佣金
    public SalaryDistributeTO getDeliverMoney(Long companyId, String username, Double orderDeliveryMoney) throws Exception {
        CityPostman cityPostman = CityPostmanMemory.getInstance().getPostman(username);
        if (cityPostman == null) {
            throw new Exception("获取骑士信息错误！");
        }
        // 首先获取当前配送公司的设置的工资规则
        PostCompanyInfo postCompanyInfo = PostCompanyMemory.getInstance().getById(companyId);
        if (postCompanyInfo == null) {
            throw new Exception("获取配送公司信息错误");
        }
        if (StringUtils.isEmpty(postCompanyInfo.getDeliverSalarySetting())) {
            throw new Exception("配送公司尚未设置公司规则！" + postCompanyInfo.getId());
        }
        SalaryDistributeTO to = new SalaryDistributeTO();
        to.setRuleSetting(postCompanyInfo.getDeliverSalarySetting());
        if (postCompanyInfo.getDeliverSalarySetting().equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_COUNT)
                || postCompanyInfo.getDeliverSalarySetting().equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_DRAW)) {
            // 根据本月订单量计算
            // 首先判断当前时间的配送公司的公司计算时间段
            int days = postCompanyInfo.getDeliverySalaryData() == 0 ? 1 : postCompanyInfo.getDeliverySalaryData();
            Date startMonthDay = DateUtils.getMonthDayByDay(days);
            Date endMonthDay = DateUtils.getMonthDayByDay(days);
            int orderCount = 0;
            PostCompanySalaryCalcInfo calcInfo = PostManAndCompanySalryCalcService.getInstance().get(username, companyId);
            if (calcInfo.getSalaryMonthDate() != null && DateUtils.isEffectiveDate(new Date(calcInfo.getSalaryMonthDate()), startMonthDay, endMonthDay)) {
                orderCount = calcInfo.getSalaryMonthCount();
            }
            orderCount += 1;
            PostCompanySalaryCountRuleInfo rule = this.getSalaryByOrderCount(postCompanyInfo.getDeliverSalarySetting(), companyId, orderCount);
            if (postCompanyInfo.getDeliverSalarySetting().equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_COUNT)) {
                to.setRuleCount(rule.getStartOrderCount() + "-" + rule.getEndOrderCount() + "(" + rule.getOrderDeliveryPrice() + ")");
                to.setPostMoney(rule.getOrderDeliveryPrice());
            } else {
                DecimalFormat decimalFormat = new DecimalFormat("#.0");
                to.setRuleCount("配送公司抽成：" + JYMathDoubleUtils.sub(1, postCompanyInfo.getDeliverySalaryproportion()));
//                to.setPostMoney(Double.parseDouble(decimalFormat.format((1 - rule.getOrderDeliveryPrice()) * orderDeliveryMoney)));
                to.setPostMoney(JYMathDoubleUtils.mul(JYMathDoubleUtils.sub(1, rule.getOrderDeliveryPrice()), orderDeliveryMoney));
            }
            to.setRuleSetting(postCompanyInfo.getDeliverSalarySetting());
            to.setOrderCount(calcInfo.getSalaryMonthCount() + 1);
        } else {
            throw new Exception("配送公司设置规则错误，请联系修改！");
        }
        to.setCompanyMoney(JYMathDoubleUtils.sub(orderDeliveryMoney, to.getPostMoney()));

        // 计算奖励金 Jahnke  2019年8月23日 10:11:07
        // 首先获取当前时间配送公司正在进行中的奖励活动
        PostCompanySalaryCountRuleInfo bounsRule = this.getBounsRule(companyId, new Date());
        if (bounsRule != null) {
            to.setAllowance(bounsRule.getOrderDeliveryPrice());
        }

        return to;
    }


    // 获取骑士当前订单可获取的佣金  (按比例时，是按配送公司的毛利润，如果骑手有奖励金，那么配送公司的毛利润里还需要再减去骑手的奖励金，再跟骑手分成)
    public SalaryDistributeTO getDeliverMoneyV2(Long companyId, String username, Double companyMoney) throws Exception {
        CityPostman cityPostman = CityPostmanMemory.getInstance().getPostman(username);
        if (cityPostman == null) {
            throw new Exception("获取骑士信息错误！");
        }
        // 首先获取当前配送公司的设置的工资规则
        PostCompanyInfo postCompanyInfo = PostCompanyMemory.getInstance().getById(companyId);
        if (postCompanyInfo == null) {
            throw new Exception("获取配送公司信息错误");
        }
        if (StringUtils.isEmpty(postCompanyInfo.getDeliverSalarySetting())) {
            throw new Exception("配送公司尚未设置公司规则！" + postCompanyInfo.getId());
        }

        SalaryDistributeTO to = new SalaryDistributeTO();
        // 计算奖励金 Jahnke  2019年8月23日 10:11:07
        // 首先获取当前时间配送公司正在进行中的奖励活动
        Double bounsMoney = 0d;
        PostCompanySalaryCountRuleInfo bounsRule = this.getBounsRule(companyId, new Date());
        if (bounsRule != null && ValidateUtil.isAbsDouble(bounsRule.getOrderDeliveryPrice())) {
            bounsMoney = bounsRule.getOrderDeliveryPrice();
            companyMoney = JYMathDoubleUtils.sub(companyMoney, bounsMoney);
        }
        to.setAllowance(bounsMoney);// 奖励金
        to.setRuleSetting(postCompanyInfo.getDeliverSalarySetting());
        if (postCompanyInfo.getDeliverSalarySetting().equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_COUNT)
                || postCompanyInfo.getDeliverSalarySetting().equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_DRAW)) {
            // 根据本月订单量计算
            // 首先判断当前时间的配送公司的公司计算时间段
            int days = postCompanyInfo.getDeliverySalaryData() == 0 ? 1 : postCompanyInfo.getDeliverySalaryData();
            Date startMonthDay = DateUtils.getMonthDayByDay(days);
            Date endMonthDay = DateUtils.getMonthDayByDay(days);
            int orderCount = 0;
            PostCompanySalaryCalcInfo calcInfo = PostManAndCompanySalryCalcService.getInstance().get(username, companyId);
            if (calcInfo.getSalaryMonthDate() != null && DateUtils.isEffectiveDate(new Date(calcInfo.getSalaryMonthDate()), startMonthDay, endMonthDay)) {
                orderCount = calcInfo.getSalaryMonthCount();
            }
            orderCount += 1;
            PostCompanySalaryCountRuleInfo rule = this.getSalaryByOrderCount(postCompanyInfo.getDeliverSalarySetting(), companyId, orderCount);
            if (postCompanyInfo.getDeliverSalarySetting().equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_COUNT)) {
                to.setRuleCount(rule.getStartOrderCount() + "-" + rule.getEndOrderCount() + "(" + rule.getOrderDeliveryPrice() + ")");
                to.setPostMoney(rule.getOrderDeliveryPrice());
            } else {
                DecimalFormat decimalFormat = new DecimalFormat("#.0");
                to.setRuleCount("配送公司抽成：" + JYMathDoubleUtils.sub(1, postCompanyInfo.getDeliverySalaryproportion()));
//                to.setPostMoney(Double.parseDouble(decimalFormat.format((1 - rule.getOrderDeliveryPrice()) * orderDeliveryMoney)));
                to.setPostMoney(JYMathDoubleUtils.mul(JYMathDoubleUtils.sub(1, rule.getOrderDeliveryPrice()), companyMoney));
            }
            to.setRuleSetting(postCompanyInfo.getDeliverSalarySetting());
            to.setOrderCount(calcInfo.getSalaryMonthCount() + 1);
        } else {
            throw new Exception("配送公司设置规则错误，请联系修改！");
        }
        to.setCompanyMoney(JYMathDoubleUtils.sub(companyMoney, to.getPostMoney()));

        return to;
    }


    // 更新骑士的按月订单工资累计
    public void addUpOrderCount2PostMan(Long companyId, String username) throws SQLException {
        // 首先获取当前配送公司的设置的工资规则
        PostCompanyInfo postCompanyInfo = PostCompanyMemory.getInstance().getById(companyId);
        if (postCompanyInfo.getDeliverSalarySetting().equals(PostCompanyInfo.DELIVERY_SALARY_SETTING_COUNT)) {
            PostCompanySalaryCalcInfo calcInfo = PostManAndCompanySalryCalcService.getInstance().get(username, companyId);
            calcInfo.setSalaryMonthCount(calcInfo.getSalaryMonthCount() == null ? 1 : calcInfo.getSalaryMonthCount() + 1);
            calcInfo.setSalaryMonthDate(System.currentTimeMillis());
            Map<String, Object> querys = new HashMap<>();
            querys.put("companyId", companyId);
            querys.put("username", username);
            try {
                UserDaoSql.getInstance().updateObj(PojoTables.POST_COMPANY_CALC_SALARY, calcInfo, querys);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            PostManAndCompanySalryCalcService.getInstance().reload(username, companyId);
        }
    }

    // 获取符合订单量的工资
    private PostCompanySalaryCountRuleInfo getSalaryByOrderCount(String type, long companyId, int orderCount) throws Exception {
        List<PostCompanySalaryCountRuleInfo> list = this.listOfCountRule(companyId, type);
        if (list == null || list.isEmpty()) {
            throw new Exception("配送公司尚未设置工资计算规则！");
        }
        PostCompanySalaryCountRuleInfo ll = null;
        for (int i = 0; i < list.size(); i++) {
            PostCompanySalaryCountRuleInfo rule = list.get(i);
            if (rule.getStartOrderCount() <= orderCount && rule.getEndOrderCount() >= orderCount) {
                return rule;
            }
        }
        throw new Exception("配送公司工资设置规则错误（本月订单量：" + orderCount + "）");
    }

    private PostCompanySalaryCountRuleInfo getBounsRule(long companyId, Date date) {
        List<PostCompanySalaryCountRuleInfo> list = this.listOfCountRule(companyId, PostCompanySalaryCountRuleInfo.SALARY_RULE_TYPE_BOUNS);
        if (list != null && !list.isEmpty()) {
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i).getRuleEndTime().getTime() >= date.getTime() && list.get(i).getRuleStartTime().getTime() < date.getTime()) {
                    return list.get(i);
                }
            }
        }
        return null;
    }

    // 骑士公司的分配信息
    public static class SalaryDistributeTO {

        private String ruleSetting;     // 规则设置（抽成，还是每月订单量）
        private String ruleCount;       // 规则数量（抽成：配送公司抽成:20%   每月订单量：100-200（5元））
        private Double postMoney = 0D;  // 骑士配送费
        private Double companyMoney;    // 配送公司获得的配送费
        private Integer orderCount;     // 订单量-本月第几单
        private Double allowance = 0D;  // 补贴金额

        public String getRuleSetting() {
            return ruleSetting;
        }

        public SalaryDistributeTO setRuleSetting(String ruleSetting) {
            this.ruleSetting = ruleSetting;
            return this;
        }

        public String getRuleCount() {
            return ruleCount;
        }

        public SalaryDistributeTO setRuleCount(String ruleCount) {
            this.ruleCount = ruleCount;
            return this;
        }

        public Double getPostMoney() {
            return postMoney;
        }

        public SalaryDistributeTO setPostMoney(Double postMoney) {
            this.postMoney = postMoney;
            return this;
        }

        public Double getCompanyMoney() {
            return companyMoney;
        }

        public SalaryDistributeTO setCompanyMoney(Double companyMoney) {
            this.companyMoney = companyMoney;
            return this;
        }

        public Integer getOrderCount() {
            return orderCount;
        }

        public SalaryDistributeTO setOrderCount(Integer orderCount) {
            this.orderCount = orderCount;
            return this;
        }

        public Double getAllowance() {
            return allowance;
        }

        public SalaryDistributeTO setAllowance(Double allowance) {
            this.allowance = allowance;
            return this;
        }
    }


    //////////////////////////////////// 奖励金规则设置 /////////////////////////////////
    // 获取配送公司的奖励金设置列表
    public List<PostCompanySalaryCountRuleInfo> list(Long companyId, String type) {
        // 自动删除所有失效超过一个月的数据
        String sql = "select * from " + PojoTables.POST_COMPANY_RULE_SALARY + " where companyId=" + companyId + " and ruleType='" + PostCompanySalaryCountRuleInfo.SALARY_RULE_TYPE_BOUNS + "'";
        List<PostCompanySalaryCountRuleInfo> list = null;
        try {
            list = (List<PostCompanySalaryCountRuleInfo>) UserDaoSql.getInstance().list(PostCompanySalaryCountRuleInfo.class, sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }
}
